﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;

namespace Argos.WMI
{
	/// <summary>
	/// Represents the <c>Win32_LogicalDisk</c> object in WMI.
	/// </summary>
	public sealed class LogicalDisk
	{

		#region #ctor: private LogicalDisk()

		/// <summary>
		/// Creates a new instance of the class.
		/// </summary>
		private LogicalDisk() { }

		#endregion



		/// <summary>
		/// Returns the description of the logical disk.
		/// </summary>
		public string Description { get; private set; }

		/// <summary>
		/// Returns the drive letter associated with the logical disk.
		/// </summary>
		public DriveLetter DriveLetter { get; private set; }

		/// <summary>
		/// Returns the drive type of the logical disk.
		/// </summary>
		public DriveType DriveType { get; private set; }

		/// <summary>
		/// Returns a string representing the kind of file system the
		/// logical disk has been formatted with.
		/// </summary>
		public string FileSystem { get; private set; }

		/// <summary>
		/// Returns the available free space on the logical disk in bytes.
		/// </summary>
		public ulong FreeSpace { get; private set; }

		/// <summary>
		/// Returns the name of the machine associated with the logical disk.
		/// </summary>
		public string MachineName { get; private set; }

		/// <summary>
		/// Returns the name or label of the logical disk.
		/// </summary>
		public string Name { get; private set; }

		/// <summary>
		/// Returns the serial number of the logical disk.
		/// </summary>
		public string SerialNumber { get; private set; }

		/// <summary>
		/// Returns the total size of the logical disk in bytes.
		/// </summary>
		public ulong Size { get; private set; }



		#region public static IList<LogicalDisk> GetDisks()

		/// <summary>
		/// Returns a list of all logical disks on the current computer.
		/// </summary>
		public static IList<LogicalDisk> GetDisks()
		{
			return GetDisks(Environment.MachineName);
		}

		#endregion
		
		#region public static IList<LogicalDisk> GetDisks(string machineName)

		/// <summary>
		/// Returns a list of all logical disks on the given computer.
		/// </summary>
		/// <param name="machineName">The name of the computer for which to return the logical disks.</param>
		public static IList<LogicalDisk> GetDisks(string machineName)
		{
			return GetDisks(machineName, new ConnectionOptions());
		}

		#endregion
		
		#region public static IList<LogicalDisk> GetDisks(string machineName, ConnectionOptions options)

		/// <summary>
		/// Returns a list of all logical disks on the given computer using the
		/// given connection options.
		/// </summary>
		/// <param name="machineName">The name of the computer for which to return the logical disks.</param>
		/// <param name="options">The options to use when connecting to the computer.</param>
		public static IList<LogicalDisk> GetDisks(string machineName, ConnectionOptions options)
		{
			List<LogicalDisk> list = new List<LogicalDisk>();

			if(string.IsNullOrEmpty(machineName))
			{
				machineName = Environment.MachineName;
			}

			ManagementScope scope = new ManagementScope(string.Format(@"\\{0}\root\cimv2", machineName), options);
			ObjectQuery query = new ObjectQuery(@"SELECT * FROM Win32_LogicalDisk");

			using (ManagementObjectSearcher search = new ManagementObjectSearcher(scope, query))
			{
				foreach (var result in search.Get())
				{
					LogicalDisk disk = new LogicalDisk();

					disk.Description = result.GetPropertyValue("Description") as string;

					string deviceId = result.GetPropertyValue("DeviceID") as string;
					disk.DriveLetter = (DriveLetter)Enum.Parse(typeof(DriveLetter), deviceId.Substring(0, 1), true);

					disk.FileSystem = result.GetPropertyValue("FileSystem") as string;

					disk.MachineName = machineName;

					disk.Name = result.GetPropertyValue("VolumeName") as string;

					disk.SerialNumber = result.GetPropertyValue("VolumeSerialNumber") as string;

					object freeSpace = result.GetPropertyValue("FreeSpace");
					if (freeSpace is ulong)
					{
						disk.FreeSpace = (ulong)freeSpace;
					}

					object size = result.GetPropertyValue("Size");
					if (size is ulong)
					{
						disk.Size = (ulong)size;
					}

					object type = result.GetPropertyValue("DriveType");
					if (type is uint)
					{
						disk.DriveType = (DriveType)(uint)type;
					}

					list.Add(disk);
				}
			}

			return list;
		}

		#endregion



		#region public override string ToString()

		/// <summary>
		/// Returns the string representation of the logical disk.
		/// </summary>
		public override string ToString()
		{
			return string.Format(@"\\{0}\{1}$", this.MachineName, this.DriveLetter);
		}

		#endregion

	}
}
